<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2022/12/11/28-特权级和特权级保护/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="1. 特权级保护的必要性和特权保护机制用描述符实施段与段之间的隔离和保护，建立在程序之间分工协作的基础上，首先用户程序需要在内核的支持下运行而不能独立运行。 内核需要加载和重定位用户程序，为用户程序每个段创建描述符，将段选择子回填到用户程序的头部中，因为这个原因用户程序只能访问自己的代码段、数据段和栈段。">
<meta property="og:type" content="article">
<meta property="og:title" content="特权级和特权级保护">
<meta property="og:url" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="1. 特权级保护的必要性和特权保护机制用描述符实施段与段之间的隔离和保护，建立在程序之间分工协作的基础上，首先用户程序需要在内核的支持下运行而不能独立运行。 内核需要加载和重定位用户程序，为用户程序每个段创建描述符，将段选择子回填到用户程序的头部中，因为这个原因用户程序只能访问自己的代码段、数据段和栈段。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b419bbd59816da11bea31176df362915.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/8301c8a1961eaafdfde4afbc833cac75.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/534123fc9756c0c8be4702bce7bde3e5.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/5ab45bab78a1b750e50617a784d7958d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e82baf2eb98a7295eaa51f004738ba24.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/1f1bc764623aea4d27976f445a600fc8.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/930d0c64fd66fcda8b7f6fb7b7578d74.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/07a549e08584fbe0e41ba5c7e84d9ad2.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/94509260f80233f558f8f1b5e7ef419c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/21e0a05746b3ca89b979aa879ef39027.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/aef51c4b0badee6b9acb78698418b58e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/bf5c5802fb0efd9aa47e3c5ea19606c3.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/357d06dc5af6b68e954f64083a703693.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/46d157cd6a850257a170db6bef97d529.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a1a23292b0b75c5a5ecea52a8711ef52.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9c63e6118a4b5d90f57026030116f767.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/7a71dc22360260834fc29c2314f4ae8a.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/179ec831c689c14a57937406b425c4a8.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/d7a0f0d99381f9de92b714d40e670c7b.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/19fb2ada53ec9c2d25bee32c3cf3efc2.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/5186d52211a8cb78f11eb44a06f5d991.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a2468104e567c496d0c363e19f33c8ce.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/838c8deb87ba21672c488901d70d756c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b15db26cb1d6aca2e7c439c29bf7778e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/33bcf125a7d94c25d79aef9e8646da2e.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/4119cb107ccd78184897262995691708.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/30e1a68b76aac209728ae085a24b8ea0.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/22c1deda038e307144472e86469a1c6c.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e604325a309c96f47dd42c8c2e3bd8c7.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/49141991bb016a8848bfa17c75991426.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/32983c8cc1a5e803ea6bf07aac2c1d15.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/23e9f4fd8b39015b6e7e6e5c8528b1ee.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/6518feaecf9fc62d080fc0d091355ed0.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/7ae4d92e523e91c9d13143d5d81db293.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/528c93b00b480f0755db858e7019c86b.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/de2084be174908ddc891a44709eb349d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b9122dfea493ddd6e1e01d87931ce2ac.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a51b09bd9abd495fbb26d503615fbe12.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e30802c6c987a49c9a97e3b200122cc7.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/36e7df3cf593f7328368b76a0c077619.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/19dfe1105f0d2f3c98eb7c2c64c36496.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9e54f5e4a7b6a8667a36e1ea17b856d7.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a0bc603ee99aac03173c64f016e9e70a.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/74e528f9b31450fde9a622b1a75eece1.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b1176d3ad6fdd9933abe8488ad1f2858.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/f7134a3acce2a32acee54711ec2cb469.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/0df927207154745600b71a08826ebcc2.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/44f4a1e4fc015ba16294623f907c5a4d.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9ab26e5173251877414c71dac2562ea7.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a23d6b3e8979060aa4a9cb178e98a27f.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/494eeae03df39fb176ef1babebb7c9b7.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/36523565de8778222c076fd55ab5ccaa.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/019882c53d7533d421d43dc588d91283.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/f0955c31ac0d10e20deec392c7112361.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/0b667250859c67753ffa8d22eea56c58.png">
<meta property="article:published_time" content="2022-12-11T14:46:00.000Z">
<meta property="article:modified_time" content="2023-10-03T05:00:06.396Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="x86特权级和特权级保护">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b419bbd59816da11bea31176df362915.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            特权级和特权级保护 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">特权级和特权级保护</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2022-12-11 22:46</span>
        <span class="mobile">2022-12-11 22:46</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-10-03 13:06</span>
            <span class="mobile">2023-10-03 13:06</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/X86%E6%B1%87%E7%BC%96%EF%BC%9A%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%88%B0%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">X86汇编：实模式到保护模式</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/x86%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/">x86特权级和特权级保护</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<h2 id="1-特权级保护的必要性和特权保护机制"><a href="#1-特权级保护的必要性和特权保护机制" class="headerlink" title="1. 特权级保护的必要性和特权保护机制"></a>1. 特权级保护的必要性和特权保护机制</h2><p>用描述符实施段与段之间的隔离和保护，建立在程序之间分工协作的基础上，首先用户程序需要在内核的支持下运行而不能独立运行。</p>
<p>内核需要加载和重定位用户程序，为用户程序每个段创建描述符，将段选择子回填到用户程序的头部中，因为这个原因用户程序只能访问自己的代码段、数据段和栈段。</p>
<span id="more"></span>

<p>当然这样并不能有效地阻止用户程序访问GDT，如下代码：</p>
<pre><code class="assembly">        mov eax, 0x28		;00101_0_00
        mov ds, eax
        mov dword[0],012345678
</code></pre>
<p>用户程序虽然不知道5号描述符指向哪个段，但是仍然可以破坏段中的数据，甚至用户可以重新定义一个新的GDT来替换内核建立的GDT，从而达到破坏的目的。</p>
<p>用户程序只要知道内核中历程的<strong>段选择子</strong>和<strong>段内偏移</strong>就可以调用例程执行，这样会很容易的破坏内核。</p>
<p>系统的多任务如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b419bbd59816da11bea31176df362915.png" class="">

<p>使用特权级来划分内核和用户程序，任务的共有部分和私有部分之间的隔离特权级从<strong>0~3</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/8301c8a1961eaafdfde4afbc833cac75.png" class="">

<p>特权指令：只有<strong>0特权级</strong>的程序能够执行</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/534123fc9756c0c8be4702bce7bde3e5.png" class="">

<h2 id="02-当前特权级CPL"><a href="#02-当前特权级CPL" class="headerlink" title="02. 当前特权级CPL"></a>02. 当前特权级CPL</h2><p>特权级是以处理器的工作特点和工作方法来划分的。</p>
<p>处理器不知道当前执行的是哪个程序，但是可以知道是哪个段：因为要用到段寄存器</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/5ab45bab78a1b750e50617a784d7958d.png" class="">

<p>程序的特权级就是：组成这个程序的所有代码的特权级。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e82baf2eb98a7295eaa51f004738ba24.png" class="">

<p>处理器正在执行哪个段，其特权级就是<strong>当前特权级CPL（Current Priviledge Level）</strong>，也即是当前正在执行的程序的特权级。</p>
<p>那么在哪里体现CPL呢？段寄存器如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/1f1bc764623aea4d27976f445a600fc8.png" class="">

<p>段选择器：低两位保存<strong>CPL</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/930d0c64fd66fcda8b7f6fb7b7578d74.png" class="">

<p>也有例外，如下：</p>
<pre><code class="assembly">         mov cr0,eax                        ;设置PE位
      
         ;以下进入保护模式... ...
         jmp dword 0x0010:flush             ;16位的描述符选择子：32位偏移
                                            ;清流水线并串行化处理器  
</code></pre>
<p>当然<strong>CR0</strong>的<strong>PE</strong>位进入保护模式之后，处理器自动处于0特权级，但是这个特权级无法使用<strong>CS</strong>的段选择器来指示，因为这时候CS的段选择器中仍然保存着实模式下的逻辑段地址，而不是段选择子。之后在执行了<strong>jmp</strong>指令之后，<strong>CS</strong>才会被刷新，用来指示当前特权级。</p>
<p>在引入保护模式和特权级之后，实模式被赋予了新的内涵，实模式下的成刷始终是<strong>0特权级的</strong>，在进入保护模式之后，处理器是继承了实模式下的<strong>0特权级</strong>。</p>
<h2 id="03-描述特权级DPL"><a href="#03-描述特权级DPL" class="headerlink" title="03. 描述特权级DPL"></a>03. 描述特权级DPL</h2><p>描述特权级**DPL(Descriptor Privilege Level)**：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/07a549e08584fbe0e41ba5c7e84d9ad2.png" class="">
<p>描述符特权级用来描述指定的<strong>实体</strong>的特权级，即描述符描述的是一个段，那么DPL就是这个段的特权级。对于一个正在执行的代码段，其<strong>CPL</strong>和当前的<strong>DPL</strong>是一致的。</p>
<p>程序在不同的代码段内执行，那么<strong>CPL</strong>就要等于目标代码段的<strong>DPL</strong>。即控制转移只能发生在两个特权级相同的代码段之间，<br>例如：<strong>CS</strong>指向<strong>代码段A</strong>、<strong>CPL = 0</strong>；<strong>代码段B</strong>的<strong>DPL</strong>要等于0<br>才能从<strong>代码段A</strong>跳转到<strong>代码段B</strong>内执行。</p>
<p>当然也可以中一个<strong>低特权级的代码段</strong>转移到一个<strong>高特权级的代码段</strong>去执行，需要特殊的方法。但是无论如何都不能从一个<strong>高特权级的代码段</strong>转移到一个<strong>低特权级的代码段</strong>内执行。</p>
<p>访问数据时的特权级：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/94509260f80233f558f8f1b5e7ef419c.png" class="">
<p>再当前代码段内访问数据段，那么<strong>当前代码段的特权级</strong>需要大于<strong>目标数据段的特权级</strong>，即<mark>CPL ≤ DPL</mark>。代码段特权级特别低的话表示其可靠性和安全性不高不允许其访问高特权级的数据段。</p>
<p>上一章代码中，从<strong>引导程序跳转执行内核程序</strong>时，两者特权级都是0，可以跳转。从内核程序跳转执行用户称刷时，两者特权级均为0，可以跳转。其中执行<strong>ldt、lldt</strong>这些只能再0特权级执行的指令也是合法的。</p>
<h2 id="04-任务公共部分和私有部分的特权级划分"><a href="#04-任务公共部分和私有部分的特权级划分" class="headerlink" title="04. 任务公共部分和私有部分的特权级划分"></a>04. 任务公共部分和私有部分的特权级划分</h2><p>一个任务由内核和用户程序共同组成，当内核为用户程序创建描述符时，将用户程序的特权级设置为3，内核的特权级设置为0。</p>
<p>在代码中：将我们之前建立程序头部段时设置的<strong>0特权级</strong>改为<strong>3</strong></p>
<pre><code class="assembly">    ;建立程序头部段描述符
    mov eax,edi                        ;程序头部起始线性地址
    mov ebx,[edi+0x04]                 ;段长度
    dec ebx                            ;段界限
    ;mov ecx,0x00409200                 ;字节粒度的数据段描述符，特权级0
    mov ecx,0x0040F200                 ;字节粒度的数据段描述符，特权级3
    call sys_routine_seg_sel:make_seg_descriptor
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/21e0a05746b3ca89b979aa879ef39027.png" class="">
<p>同上，将代码段、数据段、栈段的特权级均改为<strong>3</strong>。</p>
<p>但是只修改特权级的话程序将不能运行，因为当前内核的<strong>CPl = 0</strong>，用户程序<strong>DPL = 3</strong>，在任何情况下都是不允许<strong>jmp、call</strong>指令从高特权级向低特权级转移执行的。就算能进入用户程序，则当前的<strong>CPL = 3</strong>，在用户程序中去调用内核的例程也是不被允许的。</p>
<p>调试程序，在内核跳转执行用户程序时中断：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/aef51c4b0badee6b9acb78698418b58e.png" class="">
<p>显示特权级检查没有通过。</p>
<h2 id="05-依从的代码段"><a href="#05-依从的代码段" class="headerlink" title="05. 依从的代码段"></a>05. 依从的代码段</h2><p>处理器原则上不允许两个不同特权级的代码段转移执行，但是符合一定条件是可以的。</p>
<p><strong>方法一</strong>：将目标代码段设置为依从的代码段，<strong>依从的代码段</strong>即使其特权级较高也可以从地特权代码段进入。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/bf5c5802fb0efd9aa47e3c5ea19606c3.png" class="">

<ul>
<li>S位：为1表示储存器的段描述符</li>
<li>X位：为1表示代码段</li>
<li>C位：为0表示普通的代码段，为1表示依从的代码段，一个代码段是依从的表示可以种低特权级进入、但是不能从高特权级进入（<mark>当前代码段的CPL</mark> <strong>≤</strong> <mark>依从代码段DPL</mark>）<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/357d06dc5af6b68e954f64083a703693.png" class=""></li>
</ul>
<p>上图中右边CPL = 3可以转移到左边DPL = 2的代码段执行。转移之后程序是在CPL = 3的特权级上执行，而不是在依从代码段的DPL = 2特权级上去执行。</p>
<h2 id="06-门描述符和调用门"><a href="#06-门描述符和调用门" class="headerlink" title="06. 门描述符和调用门"></a>06. 门描述符和调用门</h2><p>接上一节。</p>
<p><strong>方法二</strong>：通过门实施转移</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/46d157cd6a850257a170db6bef97d529.png" class="">
<p>门描述符描述的是一些系统管理单元，比如描述一个任务、描述一个例程或子程序。</p>
<p>如果门描述符描述的是一个例程，就称之为调用门。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a1a23292b0b75c5a5ecea52a8711ef52.png" class="">
<p>如果高特权级是依从的，可以从<strong>低特权级</strong>向<strong>高特权级</strong>代码段转移执行。<br>若不是依从的，通过调用门也可以从<strong>低特权级</strong>向<strong>高特权级</strong>代码段转移执行。</p>
<p>调用门格式：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9c63e6118a4b5d90f57026030116f767.png" class="">

<ul>
<li>S：为0表示系统描述符</li>
<li>TYPE：为<strong>1100</strong>表示调用门、描述的是一个例程</li>
<li>P：为0表示调用门无效、为1表示有效；</li>
<li>DPL：表示调用门本身的特权级</li>
<li>高32位的0~4位：保存用栈传递的参数的个数最大能表示<strong>2^5 - 1= 31</strong>个。</li>
</ul>
<p>调用门涉及三个部分：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/7a71dc22360260834fc29c2314f4ae8a.png" class="">

<ol>
<li>当前代码段特权级CPL</li>
<li>调用门描述符的DPL</li>
<li>目标代码段描述符的DPL<br>需要符合：数值上有目标代码段描述符的DPL ≤ 当前代码段特权级CPL ≤ 调用门描述符的DPL。<br>比如这个需要CPL为1或者2的时候才能通过调用门<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/179ec831c689c14a57937406b425c4a8.png" class=""></li>
</ol>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/d7a0f0d99381f9de92b714d40e670c7b.png" class="">

<ul>
<li>用<strong>CALL</strong>指令通过调用门之后可以返回，通过之后处理器在目标代码段的特权级上执行，即CPL由低到高。</li>
<li>用<strong>JMP</strong>指令通过调用门之后不可以返回，通过之后特权级不变还是在原来的特权级上执行。</li>
</ul>
<p>调用一个例程时，可以使用寄存器和栈传递参数，调用者通过调用门之后将参数压栈，返回时从栈中返回参数。</p>
<p>但是通过调用门之后特权级可能改变当前特权级指令CPL，从低特权级变为高特权级。此时处理器要求栈也必须切换，从低特权级的栈切换到高特权级的栈，还要复制参数，为了防止栈出错调用门描述符中需要保存要传递参数的数量，保存在高32位的0~4中最多表示<strong>2^5 - 1= 31</strong>个。</p>
<h2 id="07-本章程序说明及特权级检查的时机"><a href="#07-本章程序说明及特权级检查的时机" class="headerlink" title="07. 本章程序说明及特权级检查的时机"></a>07. 本章程序说明及特权级检查的时机</h2><p>本章程序有：<br>主引导程序：c13_mbr0.asm<br>内核程序：c14_core2.asm<br>用户程序：c13_app1.asm</p>
<p>进入保护模式之后就要进行特权级指令检查，<mark>jmp far</mark>指令进入内核执行，需要进行特权级检查。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/19fb2ada53ec9c2d25bee32c3cf3efc2.png" class="">

<ol>
<li>上图中下面两行不需要进行特权级检查，虽然需要访问段中数据，但是在访问前需要指定段的位置。</li>
<li>就如前两行代码，将一个段选择子传入段寄存器DS时，要检查当前特权级CPL是否高于等于<strong>目标数据段描述符的DPL</strong>，即数值上<strong>当前CPL ≤ 目标数据段DPL</strong>。</li>
<li>若通过检查表示DS会被加载，那么后续的内存访问指令都是合法的，如果不通过检查，后续的指令就没有机会成功执行。</li>
<li>特权级检查的典型时机如下：其中特权指令只能在<strong>0特权级</strong>下执行。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/5186d52211a8cb78f11eb44a06f5d991.png" class="">
本章程序可以从0特权级的内核进入3特权级的用户程序执行，也可以在3特权级的用户程序中使用0特权级的接口例程。</li>
</ol>
<h2 id="08-请求特权级RPL"><a href="#08-请求特权级RPL" class="headerlink" title="08. 请求特权级RPL"></a>08. 请求特权级RPL</h2><p>本章程序：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a2468104e567c496d0c363e19f33c8ce.png" class="">

<ol>
<li>用户程序中<strong>CPL = 3</strong>，调用门中的<strong>DPL = 3</strong>，内核代码段的<strong>DPL = 0</strong>，满足条件可以执行转移。转移之后处理器以<strong>CPL = 0</strong>特权级执行</li>
<li>在内核的硬盘读写例程中将数据段的选择子传送给DS，需要进行特权级检查，由高特权级高特权级的代码段可以访问低特权级或同级的数据段，在本程序中硬盘读写例程中<strong>CPL = 0</strong> ≤ 用户程序数据段的<strong>DPL = 3</strong>，即满足条件通过检查。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/838c8deb87ba21672c488901d70d756c.png" class="">
若用户程序通过调用门执行内核的硬盘的读写例程时传递的<strong>数据段选择子是内核数据段选择子</strong>，那么在将数据段选择子传递给DS时也可以通过检查，那么用户程序就可以通过调用门破坏内核数据段了。</li>
</ol>
<p>说明只是依靠<strong>当前代码段特权级CPL</strong>和<strong>目标数据段描述符特权级DPL</strong>进行特权级检查时不够充分的。</p>
<p>在这里要访问数据段的是用户程序，用户程序自己不能访问外部设备，它需要通过请求内核硬盘读写例程去访问一个数据段，在内核硬盘读写例程中当前<strong>CPL = 0</strong>，之前是3，说明请求者的信息被隐藏了。</p>
<p>如果能够恢复请求者身份，知道它是3级特权的用户程序，就能够知道不允许它去访问<strong>0特权级</strong>的内核数据段，将内核数据段选择子传递到DS的请求也就不可能执行，这个问题不能只靠处理器来解决。</p>
<p>在访问一个数据段之前，需要将段选择子传送到DS的段选择器，在进行这个操作时进行特权级检查<br>段选择子：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b15db26cb1d6aca2e7c439c29bf7778e.png" class="">
<p>其中RPL（Request Privilege Level）表示请求者的特权级，那么检查如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/33bcf125a7d94c25d79aef9e8646da2e.png" class="">
<p>对于RPL的检查已经内置到处理器中，由处理器固件完成的是一个例行的操作。因此当程序员意识到请求着不是当前程序或当前代码段，而是一个低特权级的程序，那么在硬盘读写例程中：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/4119cb107ccd78184897262995691708.png" class="">
<p>此时就可以检查出请求者的特权级RPL低于内核数据段特权级DPL，在数值上有<strong>RPL = 3 ≥ DPL = 0</strong>，不满足条件，指令终止处理器产生一个异常中断。</p>
<h2 id="09-请求特权级调整指令ARPL"><a href="#09-请求特权级调整指令ARPL" class="headerlink" title="09. 请求特权级调整指令ARPL"></a>09. 请求特权级调整指令ARPL</h2><p>在程序中：</p>
<pre><code class="assembly">;-------------------------------------------------------------------------------
    ;此例程用于说明如何通过请求特权级RPL解决因请求者身份与CPL不同而带来的安全问题
    read_hard_disk_with_gate:		;从硬盘读取一个逻辑扇区
                                    ;输入：PUSH 逻辑扇区号
                                    ;      PUSH 目标缓冲区所在段的选择子
                                    ;      PUSH 目标缓冲区在段内的偏移量
                                    ;返回：无
    push eax
    push ebx
    push ecx
    
    mov ax,[esp+0x10]				;获取调用者的CS
    arpl [esp+0x18],ax              ;将数据段选择子调整到真实的请求特权级别
    mov ds,[esp+0x18]               ;用真实的段选择子加载段寄存器DS
    
    mov eax,[esp+0x1c]              ;从栈中取得逻辑扇区号
    mov ebx,[esp+0x14]              ;从栈中取得缓冲区在段内的偏移量
    
    ;此部分的功能是读硬盘，并传送到缓冲区，予以省略。
    
    retf 12
</code></pre>
<p>假定已经为这个例程创建调用门，调用门的特权级是3，这个例程可以从特权级3的用户程序调用。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/30e1a68b76aac209728ae085a24b8ea0.png" class="">
<p>在CS的低2位就是进入当前例程前请求者的特权级，将其取出传送给数据段选择子的RPL字段，即可修改请求者的特权级。使用ARPL指令修改。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/22c1deda038e307144472e86469a1c6c.png" class="">
<p>ARPL指令比较两个操作数的低2位，若<strong>目的操作数RPL</strong> &lt; <strong>源操作数RPL</strong>，则修改目的操作数的RPL，使其与源操作数RPL保持一致，同时标志寄存器的0标志位<strong>ZF = 1</strong>。否则不改变目的操作数的RPL，标志寄存器的0标志位<strong>ZF清零</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e604325a309c96f47dd42c8c2e3bd8c7.png" class="">
<p>代码最后，指令<strong>retf 12</strong>表示由被调用者来保持堆栈平衡，传入三个参数，一个参数4个字节，共12个字节。</p>
<h2 id="10-一般情况下的请求特权级设置"><a href="#10-一般情况下的请求特权级设置" class="headerlink" title="10. 一般情况下的请求特权级设置"></a>10. 一般情况下的请求特权级设置</h2><p>绝大多数时候，请求者就是当前代码段或者当前程序，此时只需要将段选择子的RPL设置成当前当前特权级CPL就可以了。<br><mark>c13_mbr0.asm</mark>程序中：</p>
<pre><code class="assembly">         ;以下进入保护模式... ...
         jmp dword 0x0010:flush             ;16位的描述符选择子：32位偏移
                                            ;清流水线并串行化处理器  
</code></pre>
<ol>
<li>此时当前特权级<strong>CPL为0</strong>，是从实模式继承来的；</li>
<li>请求特权级<strong>RPL</strong>位于选择子<mark>0x0010 = 0000000000010_0_00</mark>中，其中<strong>RPL = 0</strong>；</li>
<li>转移的目标位置是初始代码段，其中DPL为00。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/49141991bb016a8848bfa17c75991426.png" class="">
因此在此条指令执行时，<strong>CPL = RPL = DPL</strong>，可以通过特权级检查。</li>
</ol>
<p>进入保护模式设置数据段：</p>
<pre><code class="assembly">    mov eax, 0x0008		;0x0008 = 0000000000001_0_00 
    mov ds, eax
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/32983c8cc1a5e803ea6bf07aac2c1d15.png" class="">

<ol>
<li>此时<strong>CPL = 0</strong>；</li>
<li>请求特权级在选择子<strong>0x0008</strong>，即请求特权级<strong>RPL = 0</strong>；</li>
<li>目标数据段是4G字节数据段，其中描述符<strong>DPL = 0</strong>;<br>能够通过特权级检查</li>
</ol>
<p>接下来设置栈段：</p>
<pre><code class="assembly">    mov eax,0x0018                      ;加载堆栈段选择子 11：00011_0_00
    mov ss,eax
    xor esp,esp                         ;堆栈指针 &lt;- 0 
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/23e9f4fd8b39015b6e7e6e5c8528b1ee.png" class="">

<ol>
<li>此时CPL = 0；</li>
<li>请求特权级在选择子0x0018，即请求特权级RPL = 0；</li>
<li>目标数据段是栈段，其描述符中DPL = 0；</li>
<li>能够通过特权级检查</li>
</ol>
<h2 id="11-为内核接口例程创建调用门"><a href="#11-为内核接口例程创建调用门" class="headerlink" title="11. 为内核接口例程创建调用门"></a>11. 为内核接口例程创建调用门</h2><p>进入内核之后使用指令<strong>call sys_routing_seg_sel:put_string</strong>在内核中转移是允许的，因为<strong>内核公共例程段的特权级</strong>和<strong>内核代码段的特权级</strong>是相同的，都是0特权级可以直接调用。但是用户程序的特权级是3，所以要为那些提供给用户程序使用的例程创建调用门。</p>
<p>在内核的核心数据段中定义了符号地址检索表，其中有例程的名字，例程所在段的段内偏移，例程所在段的段内选择子。现在分别为这些例程创建调用门，并且把它们<strong>例程所在段选择子</strong>改为<strong>调用门选择子</strong>。</p>
<p>创建调用门的代码如下：</p>
<pre><code class="assembly">         ;以下开始安装为整个系统服务的调用门。特权级之间的控制转移必须使用门
         mov edi,salt                       ;C-SALT表的起始位置
         mov ecx,salt_items                 ;C-SALT表的条目数量
  .b3:
         push ecx
         mov eax,[edi+256]                  ;该条目入口点的32位偏移地址
         mov bx,[edi+260]                   ;该条目入口点的段选择子
         mov cx,1_11_0_1100_000_00000B      ;特权级3的调用门(3以上的特权级才
                                            ;允许访问)，0个参数(因为用寄存器
                                            ;传递参数，而没有用栈)
         call sys_routine_seg_sel:make_gate_descriptor
         call sys_routine_seg_sel:set_up_gdt_descriptor
         mov [edi+260],cx                   ;将返回的门描述符选择子回填，此时默认RPL=0
         add edi,salt_item_len              ;指向下一个C-SALT条目
         pop ecx
         loop .b3
</code></pre>
<p>其中调用门描述符：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/6518feaecf9fc62d080fc0d091355ed0.png" class="">

<p>安装调用门之后的GDT布局：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/7ae4d92e523e91c9d13143d5d81db293.png" class="">



<h2 id="12-调用门测试和调用门转移过程"><a href="#12-调用门测试和调用门转移过程" class="headerlink" title="12. 调用门测试和调用门转移过程"></a>12. 调用门测试和调用门转移过程</h2><p>接上一节，本节对代码段进行测试：</p>
<pre><code class="assembly">    ;对门进行测试
    mov ebx,message_2
    call far [salt_1+256]				;通过门显示信息(偏移量将被忽略)
                                        ;此时DS指向内核数据段
    
    mov ebx,message_3
    call sys_routine_seg_sel:put_string ;在内核中调用例程不需要通过门
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/528c93b00b480f0755db858e7019c86b.png" class="">

<ol>
<li>DS是指向内核数据段，偏移<strong>salt_1+256</strong>指向一个地址，地址处存放的是一个偏移和一个选择子；</li>
<li>处理器使用段选择子到GDT中取出描述符，发现是一个调用门描述符，包含一个代码段选择子和段内偏移；</li>
<li>处理器将代码段选择子传送到CS的段选择器部分，将段内偏移传送到EIP；</li>
<li>处理器使用CS段选择器中的选择子访问GDT，将取出的描述符存放到CS描述符高速缓存器；</li>
<li>处理器使用CS描述符高速缓存器加上EIP中的偏移转移到目标例程开始执行</li>
</ol>
<p>在这里<strong>salt_1+256</strong>地址处指定的偏移量和选择子中，只是使用了选择子部分。即再通过调用门实施控制转移时，在指令中提供的偏移量会被忽略。但是在指令中偏移量还是要加上。如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/de2084be174908ddc891a44709eb349d.png" class="">
<p>若0x0030指定的选择子是一个调用门，那么指令中指定的偏移量0x0000C000不会被使用，但是在书写时不能不写，但是可以写一个任意值。</p>
<p>通过调用门实施控制转移时的特权级检查</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b9122dfea493ddd6e1e01d87931ce2ac.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a51b09bd9abd495fbb26d503615fbe12.png" class="">


<h2 id="13-通过调用门实施由低特权级到高特权级的转移"><a href="#13-通过调用门实施由低特权级到高特权级的转移" class="headerlink" title="13. 通过调用门实施由低特权级到高特权级的转移"></a>13. 通过调用门实施由低特权级到高特权级的转移</h2><p>接上一节，本节具体看代码<strong>c14_core2.asm</strong></p>
<p>其中用户程序调用内核例程和过程：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/e30802c6c987a49c9a97e3b200122cc7.png" class="">
<p>特权级检查：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/36e7df3cf593f7328368b76a0c077619.png" class="">


<h2 id="14-通过调用门转移控制时的栈切换过程"><a href="#14-通过调用门转移控制时的栈切换过程" class="headerlink" title="14. 通过调用门转移控制时的栈切换过程"></a>14. 通过调用门转移控制时的栈切换过程</h2><p>用<strong>CALL</strong>指令通过调用门实施控制转移可以改变程序的当前特权级<strong>CPL</strong>。比如从用户程序的3特权级用call指令通过调用门进入内核程序后，当前的CPL也会变为0特权级。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/19dfe1105f0d2f3c98eb7c2c64c36496.png" class="">

<p>问题在于通过调用门转移的时候，栈的切换时处理器自动进行的，那么处理器是如何知道应该切换到哪一个栈，又是如何知道栈在哪里的呢。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9e54f5e4a7b6a8667a36e1ea17b856d7.png" class="">
<p>TSS中没有保存3特权级栈段选择子和栈指针时因为通过调用门转移时，是从低特权级转移到高特权级中，特权级3是最低的，不可能从更低的特权级转移到3特权级中了，所以TSS中也就不需要存储特权级3的栈段选择子和栈指针。</p>
<p>在用户程序中：</p>
<pre><code class="assembly">         mov eax,100                         ;逻辑扇区号100
         mov ebx,buffer                      ;缓冲区偏移地址
         call far [fs:ReadDiskData]          ;段间调用 
</code></pre>
<p><strong>call far</strong>指令执行时，当前CPL = 3，目标例程位于内核的公共例程段，内核的公共例程段的特权级DPL = 0，因此进入目标例程时需要对栈进行切换。</p>
<p>切换之前的栈时用户程序自己的栈，若转移之前需要通过栈传递参数则存在用户程序自己的栈中，此处并未使用栈传递参数，而是通过寄存器传递参数。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a0bc603ee99aac03173c64f016e9e70a.png" class="">

<ol>
<li>一旦处理器发现特权级更改就要对栈进行切换，而目标代码段的特权级是0；</li>
<li>然后立即到当前任务的TSS中，取出特权级0的栈段选择子<strong>SS0</strong>、和栈指针<strong>EIP0</strong>；</li>
<li>分别传送到栈段寄存器<strong>SS</strong>和栈指针寄存器<strong>ESP</strong>；</li>
<li><strong>SS</strong>的段选择器部分发生改变后，处理器立即根据段选择子到GDT/LDT中取出描述符</li>
<li>将取出的描述符传送到<strong>SS</strong>描述符高速缓存器中，这样新的栈段就可以使用了。<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/74e528f9b31450fde9a622b1a75eece1.png" class="">
切换到新栈之后，处理器立即压入旧栈的<strong>SS和ESP</strong>，这样做是为了当从调用门返回时，可以返回到用户程序原来自己的栈中。其中段选择子是16位的，压入时使用<strong>movsz</strong>指令0扩展至32位。接着处理器将旧栈中的参数传递到新栈中（参数个数记录在调用门描述符高32位的0~4)。因为在这个调用中使用的是寄存器传参，所以这里参数部分是没有的。</li>
</ol>
<p>复制完参数之后，处理器再将控制转移前的CS和EIP压栈，这样做是为了能够返回到原来的程序，也就是调用者那里。</p>
<p>栈切换的过程是由处理器自动进行的，现在处理器就可以执行目标例程了。</p>
<p>当例程返回时：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/b1176d3ad6fdd9933abe8488ad1f2858.png" class="">
<p>从被调用程序的栈中返回<strong>SS、ESP、CS、EIP</strong>，如此一来就可以返回到原来的调用者那里去执行原来的程序，并切换回原来的旧栈。</p>
<h2 id="15-通过调用门转移控制并返回的完整描述"><a href="#15-通过调用门转移控制并返回的完整描述" class="headerlink" title="15. 通过调用门转移控制并返回的完整描述"></a>15. 通过调用门转移控制并返回的完整描述</h2><p>通过调用门转移控制并返回的全过程：<br>使用<strong>call far</strong>指令通过调用门转移控制时，如果改变了当前的特权级别则必须切换栈，即从当前任务的固有栈切换到切换到与目标代码段相同特权级别的栈上。</p>
<p>栈的切换是由处理器固件自动进行的，当前栈是由<strong>SS和ESP</strong>的当前内容指示的，要切换到的新栈位于当前任务的<strong>TSS</strong>中，处理器知道如何找到它。在栈切换前处理器要检查新栈是否有足够的空间完成本次控制转移。</p>
<p>控制转移和栈切换的过程如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/f7134a3acce2a32acee54711ec2cb469.png" class="">
<p>如果调用门的控制转移是由<strong>jmp far</strong>指令发起的，则转移后不再返回，而且没有特权级的变化就不需要切换栈；<br>相反，如果调用门的控制转移是由<strong>call far</strong>指令发起的，那么可以使用远转移指令<strong>retf</strong>返回到调用者。</p>
<p>返回时，处理器从栈中弹出调用者的<strong>代码段选择子</strong>和<strong>指令指针</strong>，不管是从相同的特权级还是从不同的特权级返回，为了安全处理器都会进行特权级检查，控制返回的全过程如下：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/0df927207154745600b71a08826ebcc2.png" class="">
<p>特权级检查不是在实际访问时进行的，而是在将段选择子带入寄存器时进行的，因此当控制低特权级的段通过调用门进入高特权级的段之后，假如高特权级的段使用指令<strong>mov ds, …</strong> 将一个高特权级的数据段选择子带入DS时，如果能够通过特权级检查时没有问题的。</p>
<p>在返回第特权级的段后，低特权级的程序依然能够使用指令<mark>mov [xx], xx</mark>来访问高特权级的数据段，而不会进行任何检查，这是很危险的。为了解决这个问题，在执行<strong>retf</strong>时处理器要检查数据段寄存器，根据他们找到相应的段描述符，要是有任意一个段描述符的DPL高于调用者的特权级也就是返回后的新CPL，那么处理器将会把数值0传送到该段寄存器的段选择器中（0是一个特殊的段选择子，处理器允许传入而且不会引发任何异常），但是后续使用这样的段选择器访问内存时一定会引发处理器异常中断。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/44f4a1e4fc015ba16294623f907c5a4d.png" class="">
<p>TSS中的SS0、ESP0等是静态的，除非软件修改它们，处理是不会修改它们的。当处理器通过调用门进入特权级0的代码段时，处理器会使用SS0和ESP0切换到特权级0的栈段，在此之后栈指针可能会因为压栈出栈而改变，但是返回时并不会更新到TSS中的ESP0，下次通过调用门进入特权级0的代码段时，用的依然是静态的ESP0的值。</p>
<h2 id="16-创建0、1、2特权级的栈并登记在TSS中"><a href="#16-创建0、1、2特权级的栈并登记在TSS中" class="headerlink" title="16. 创建0、1、2特权级的栈并登记在TSS中"></a>16. 创建0、1、2特权级的栈并登记在TSS中</h2><p>上一节介绍了通过调用门转移控制和返回的全过程，据此知道必须要创建<strong>特权级为0、1、2</strong>的栈段，并登记在当前任务的任务状态段<strong>TSS</strong>中，对于每一个栈包括栈的线性基地址、栈段选择子、初始栈指针。先把这些信息保存到TCB最后再来填写TSS。</p>
<p>在<strong>load_relocate_program</strong>程序中，处理完SALT之后，从栈中取得TCB的线性基地址，之后就可以创建0、1、2特权级的栈段了：</p>
<pre><code class="assembly">    mov esi,[ebp+11*4]                  ;从堆栈中取得TCB的基地址
    
    ;创建0特权级栈
    mov ecx,0                           ;以4KB为单位的栈段界限值
    mov [es:esi+0x1a],ecx               ;登记0特权级栈界限到TCB
    inc ecx
    shl ecx,12                          ;乘以4096，得到段大小
    push ecx
    call sys_routine_seg_sel:allocate_memory
    mov [es:esi+0x1e],ecx               ;登记0特权级栈基地址到TCB
    mov eax,ecx
    mov ebx,[es:esi+0x1a]               ;段长度（界限）
    mov ecx,0x00c09200                  ;4KB粒度，读写，特权级0
    call sys_routine_seg_sel:make_seg_descriptor
    mov ebx,esi                         ;TCB的基地址
    call fill_descriptor_in_ldt
    ;or cx,0000_0000_0000_0000          ;设置选择子的特权级为0
    mov [es:esi+0x22],cx                ;登记0特权级堆栈选择子到TCB
    pop dword [es:esi+0x24]             ;登记0特权级堆栈初始ESP到TCB
                                        ;对于一个向上扩展的栈；来说，初始栈指针
                                        ;应该设置成栈的总大小
</code></pre>
<p>创建<strong>0、1、2特权级栈</strong>之后任务控制块<strong>TCB的结构如下</strong>：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/9ab26e5173251877414c71dac2562ea7.png" class="">

<p>创建完<strong>3个特权级栈</strong>之后，先创建<strong>LDT</strong>描述符，并将其安装在<strong>GDT</strong>中，之后创建任务状态段<strong>TSS</strong>。</p>
<pre><code class="assembly">    ;在GDT中登记LDT描述符
    mov eax,[es:esi+0x0c]              ;LDT的起始线性地址
    movzx ebx,word [es:esi+0x0a]       ;LDT段界限
    mov ecx,0x00008200                 ;LDT描述符，特权级0
    call sys_routine_seg_sel:make_seg_descriptor
    call sys_routine_seg_sel:set_up_gdt_descriptor
    mov [es:esi+0x10],cx               ;登记LDT选择子到TCB中
    
    ;创建用户程序的TSS
    mov ecx,104                        ;tss的基本尺寸
    mov [es:esi+0x12],cx              
    dec word [es:esi+0x12]             ;登记TSS界限值到TCB 
    call sys_routine_seg_sel:allocate_memory
    mov [es:esi+0x14],ecx              ;登记TSS基地址到TCB
</code></pre>
<p>之后从TCB中取出<strong>0、1、2</strong>三个特权级的栈段选择子和栈指针，并填写到<strong>TSS</strong>中：</p>
<pre><code class="assembly">    ;登记基本的TSS表格内容
    mov edx,[es:esi+0x24]              ;登记0特权级栈初始ESP
    mov [es:ecx+4],edx                 ;到TSS中
    
    mov dx,[es:esi+0x22]               ;登记0特权级栈段选择子
    mov [es:ecx+8],dx                  ;到TSS中
    
    mov edx,[es:esi+0x32]              ;登记1特权级栈初始ESP
    mov [es:ecx+12],edx                ;到TSS中
    
    mov dx,[es:esi+0x30]               ;登记1特权级栈段选择子
    mov [es:ecx+16],dx                 ;到TSS中
    
    mov edx,[es:esi+0x40]              ;登记2特权级栈初始ESP
    mov [es:ecx+20],edx                ;到TSS中
    
    mov dx,[es:esi+0x3e]               ;登记2特权级栈段选择子
    mov [es:ecx+24],dx                 ;到TSS中
    
    mov dx,[es:esi+0x10]               ;登记任务的LDT选择子
    mov [es:ecx+96],dx                 ;到TSS中
    
    mov word [es:ecx+100],0            ;T=0
</code></pre>
<p>之后就是创建<strong>TSS</strong>描述符，并在GDT中登记TSS描述符：</p>
<pre><code class="assembly">    ;在GDT中登记TSS描述符
    mov eax,[es:esi+0x14]              ;TSS的起始线性地址
    movzx ebx,word [es:esi+0x12]       ;段长度（界限）
    mov ecx,0x00008900                 ;TSS描述符，特权级0
    call sys_routine_seg_sel:make_seg_descriptor
    call sys_routine_seg_sel:set_up_gdt_descriptor
    mov [es:esi+0x18],cx               ;登记TSS选择子到TCB
</code></pre>
<p>之后就是<mark>ret 8</mark>指令返回到调用者。</p>
<h2 id="17-通过模拟调用门返回进入用户程序执行"><a href="#17-通过模拟调用门返回进入用户程序执行" class="headerlink" title="17. 通过模拟调用门返回进入用户程序执行"></a>17. 通过模拟调用门返回进入用户程序执行</h2><p>接上一节，返回到内核<strong>start</strong>调用者之后，加载任务寄存器<strong>TR</strong>以及局部描述符表寄存器<strong>LDTR</strong>：</p>
<pre><code class="assembly">    ltr [ecx+0x18]		;加载任务状态段
    lldt [ecx+0x10]		;加载LDT
</code></pre>
<p>这两条指令执行之后表明当前正在一个任务中执行，现在是在任务的全局部分执行，并且应该转移到任务的私有部分（用户程序）执行。</p>
<p>在用户程序中每个段的描述符特权级<strong>DPL = 3</strong>，以前使用<strong>jmp</strong>指令完成转移，但是当前程序特权级CPL = 0，从高特权级使用<strong>jmp</strong>或<strong>call</strong>指令转移到低特权级时不被允许的。</p>
<p>通过模拟从调用门返回进入低特权级的用户程序中执行，在栈中压入以下部分：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/a23d6b3e8979060aa4a9cb178e98a27f.png" class="">

<p>代码如下：</p>
<pre><code class="assembly">    mov ds,[ecx+0x44]		;切换到用户程序头部段
                            ;使用DS取得数据，之后再回头修改DS
    
    ;以下假装是从调用门返回。摹仿处理器压入返回参数
    push dword [0x1c]		;调用前的堆栈段选择子
    push dword 0			;调用前的esp
    
    push dword [0x0c]		;调用前的代码段选择子
    push dword [0x08]		;调用前的eip
    
    retf
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/494eeae03df39fb176ef1babebb7c9b7.png" class="">
<p>之后进入用户程序执行，执行完成之后返回：</p>
<pre><code class="assembly">        jmp far [fs:TerminatePorgram]			;将控制权返回到系统
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/36523565de8778222c076fd55ab5ccaa.png" class="">
<p>但是<strong>jmp</strong>执行时，<strong>CPL = 3，DPL = 0</strong>，条件不成立，不能使<strong>jmp</strong>指令返回，这里改成<strong>call far</strong>即可，不过<strong>call</strong>指令会在栈中压入返回地址。不过在用户程序终止后，其占用的资源都会被回收，包括栈段，这种情况下压入数据和不压入数据是一样的。</p>
<p>Virtual Box运行：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/019882c53d7533d421d43dc588d91283.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/f0955c31ac0d10e20deec392c7112361.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/28-%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/0b667250859c67753ffa8d22eea56c58.png" class="">


		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> 特权级和特权级保护</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2022-12-11 22:46:00</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-10-03 13:00:06
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2022/12/11/28-特权级和特权级保护/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/x86%E7%89%B9%E6%9D%83%E7%BA%A7%E5%92%8C%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4/">#x86特权级和特权级保护</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2022/12/11/29-%E5%8D%8F%E5%90%8C%E5%BC%8F%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">协同式任务切换</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2022/12/11/27-%E4%BB%BB%E5%8A%A1%E5%92%8C%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%88%9B%E5%BB%BA/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">任务和任务的创建</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">特权级和特权级保护</div>
		<ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E7%89%B9%E6%9D%83%E7%BA%A7%E4%BF%9D%E6%8A%A4%E7%9A%84%E5%BF%85%E8%A6%81%E6%80%A7%E5%92%8C%E7%89%B9%E6%9D%83%E4%BF%9D%E6%8A%A4%E6%9C%BA%E5%88%B6"><span class="nav-text">1. 特权级保护的必要性和特权保护机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E5%BD%93%E5%89%8D%E7%89%B9%E6%9D%83%E7%BA%A7CPL"><span class="nav-text">02. 当前特权级CPL</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-%E6%8F%8F%E8%BF%B0%E7%89%B9%E6%9D%83%E7%BA%A7DPL"><span class="nav-text">03. 描述特权级DPL</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E4%BB%BB%E5%8A%A1%E5%85%AC%E5%85%B1%E9%83%A8%E5%88%86%E5%92%8C%E7%A7%81%E6%9C%89%E9%83%A8%E5%88%86%E7%9A%84%E7%89%B9%E6%9D%83%E7%BA%A7%E5%88%92%E5%88%86"><span class="nav-text">04. 任务公共部分和私有部分的特权级划分</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-%E4%BE%9D%E4%BB%8E%E7%9A%84%E4%BB%A3%E7%A0%81%E6%AE%B5"><span class="nav-text">05. 依从的代码段</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#06-%E9%97%A8%E6%8F%8F%E8%BF%B0%E7%AC%A6%E5%92%8C%E8%B0%83%E7%94%A8%E9%97%A8"><span class="nav-text">06. 门描述符和调用门</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#07-%E6%9C%AC%E7%AB%A0%E7%A8%8B%E5%BA%8F%E8%AF%B4%E6%98%8E%E5%8F%8A%E7%89%B9%E6%9D%83%E7%BA%A7%E6%A3%80%E6%9F%A5%E7%9A%84%E6%97%B6%E6%9C%BA"><span class="nav-text">07. 本章程序说明及特权级检查的时机</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#08-%E8%AF%B7%E6%B1%82%E7%89%B9%E6%9D%83%E7%BA%A7RPL"><span class="nav-text">08. 请求特权级RPL</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#09-%E8%AF%B7%E6%B1%82%E7%89%B9%E6%9D%83%E7%BA%A7%E8%B0%83%E6%95%B4%E6%8C%87%E4%BB%A4ARPL"><span class="nav-text">09. 请求特权级调整指令ARPL</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E4%B8%80%E8%88%AC%E6%83%85%E5%86%B5%E4%B8%8B%E7%9A%84%E8%AF%B7%E6%B1%82%E7%89%B9%E6%9D%83%E7%BA%A7%E8%AE%BE%E7%BD%AE"><span class="nav-text">10. 一般情况下的请求特权级设置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E4%B8%BA%E5%86%85%E6%A0%B8%E6%8E%A5%E5%8F%A3%E4%BE%8B%E7%A8%8B%E5%88%9B%E5%BB%BA%E8%B0%83%E7%94%A8%E9%97%A8"><span class="nav-text">11. 为内核接口例程创建调用门</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E8%B0%83%E7%94%A8%E9%97%A8%E6%B5%8B%E8%AF%95%E5%92%8C%E8%B0%83%E7%94%A8%E9%97%A8%E8%BD%AC%E7%A7%BB%E8%BF%87%E7%A8%8B"><span class="nav-text">12. 调用门测试和调用门转移过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8%E9%97%A8%E5%AE%9E%E6%96%BD%E7%94%B1%E4%BD%8E%E7%89%B9%E6%9D%83%E7%BA%A7%E5%88%B0%E9%AB%98%E7%89%B9%E6%9D%83%E7%BA%A7%E7%9A%84%E8%BD%AC%E7%A7%BB"><span class="nav-text">13. 通过调用门实施由低特权级到高特权级的转移</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8%E9%97%A8%E8%BD%AC%E7%A7%BB%E6%8E%A7%E5%88%B6%E6%97%B6%E7%9A%84%E6%A0%88%E5%88%87%E6%8D%A2%E8%BF%87%E7%A8%8B"><span class="nav-text">14. 通过调用门转移控制时的栈切换过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8%E9%97%A8%E8%BD%AC%E7%A7%BB%E6%8E%A7%E5%88%B6%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%9A%84%E5%AE%8C%E6%95%B4%E6%8F%8F%E8%BF%B0"><span class="nav-text">15. 通过调用门转移控制并返回的完整描述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-%E5%88%9B%E5%BB%BA0%E3%80%811%E3%80%812%E7%89%B9%E6%9D%83%E7%BA%A7%E7%9A%84%E6%A0%88%E5%B9%B6%E7%99%BB%E8%AE%B0%E5%9C%A8TSS%E4%B8%AD"><span class="nav-text">16. 创建0、1、2特权级的栈并登记在TSS中</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-%E9%80%9A%E8%BF%87%E6%A8%A1%E6%8B%9F%E8%B0%83%E7%94%A8%E9%97%A8%E8%BF%94%E5%9B%9E%E8%BF%9B%E5%85%A5%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C"><span class="nav-text">17. 通过模拟调用门返回进入用户程序执行</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>